<?php

namespace App\Console\Commands;

use App\Models\Base;
use App\Models\OldSystem\Aftersale;
use App\Models\OldSystem\Order;
use App\Models\OldSystem\User;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redis;

class MigrateOldSystemAgentPerformance extends Command
{
    /**
     * 命令名称及签名
     *
     * @var string
     */
    protected $signature = 'migrate:agent_performance';

    /**
     * 命令描述
     *
     * @var string
     */
    protected $description = '迁移老系统的代理商个人业绩';

    /**
     * 代理商总数
     * @var int
     */
    protected $agentCount = 0;

    public function handle()
    {
        /**
         * 整体迁移脚本分三部分,按照顺序执行
         * 一. 代理基本信息 MigrateOldSystemAgentBasicData
         * 二. 代理个人业绩,还有密码 (当前) (优化为 可以分多个进程执行)
         * 三. 团队业绩 (优化为 可以分多个进程执行) MigrateOldSystemAgentTeamPerformance
         */
        $this->agentCount = User::query()->count();
        $bar = $this->output->createProgressBar($this->agentCount);
        $bar->start();
        User::query()
            ->select(['user_id', 'password'])
            ->each(function (User $agent) use (&$bar) {
                try {
                    // 这里就一个 update, 不需要事务

                    $userId = $agent['user_id'];
                    // 是否已经完成过了
                    if (0 !== Redis::hexists('migrate:agent_performance', $userId)) {
                        return true;
                    }

                    // 获取单个用户操作锁
                    // 一小时的锁 ... 太长就有问题了, 这用户也太厉害了
                    Cache::lock('migrate:agent_' . $userId . '_performance_lock', 1 * 60 * 60)
                        ->get(function () use ($userId, $agent) {
                            $performance = $this->performance($userId); // 个人业绩
                            [$agentNumberOfDirectInvite, $agentNumberOfIndirectInvite] = $this->teamStructure($userId); // 邀请人数,上下级关系存在 redis

                            \DB::table('agents')->where('id', $userId)->update([
                                'personal_performance' => $performance,
                                'password' => Hash::make($agent['password']),
                                'number_of_direct_inviter' => $agentNumberOfDirectInvite,
                                'number_of_indirect_inviter' => $agentNumberOfIndirectInvite,
                            ]);

                            // 记录用户个人业绩 (也作为完成操作标识)
                            Redis::hset('migrate:agent_performance', $userId, $performance);
                        });

                    $bar->advance(1);
                } catch (\Exception $e) {
                    $this->output->error($e->getMessage());
                }

                return true;
            }, 2000);
        $bar->finish();
    }

    /**
     * 个人业绩
     * @param $userId
     * @return mixed
     */
    public function performance($userId)
    {
        $performance = 0;
        Order::query()
            ->leftJoin('aftersale_order', 'order.order_id', '=', 'aftersale_order.order_id')
            ->whereNull('aftersale_order.aftersale_order_id') // 排除存在于 sdj_aftersale_order 的订单, 换货会在 order 表产生新的订单数据
            // 售后订单
            ->with(['afterSale' => function (HasMany $hasMany) {
                $hasMany
                    ->whereIn('type', ['refund', 'back']) // 类型: 退款 退货
                    ->where('status', Aftersale::STATUS_EXAMINATION_PASSED)
                    ->select(['order_id', 'refund_amount']);
            }])
            ->whereIn('order.status', [Order::STATUS_TO_BE_DELIVERED, Order::STATUS_SHIPPED])
            ->where('order.user_id', $userId)
            ->select(['order.order_id', 'order.order_amount'])
            ->each(function (Order $order) use (&$performance) {
                $orderAmount = (int) (((float) $order['order_amount']) * Base::CURRENCY_UNIT_CONVERSION); // 订单价格
                $afterSaleOrderAmount = 0; // 订单的售后订单
                if ($order['after_sale'] !== null) {
                    $afterSaleOrderAmount = array_sum(array_column($order['after_sale'], 'refund_amount')) * Base::CURRENCY_UNIT_CONVERSION;
                }
                $orderPerformance = $orderAmount - (int) $afterSaleOrderAmount; // 订单业绩

                $performance += $orderPerformance < 0 ? 0 : $orderPerformance;
            }, 5000);

        return $performance;
    }

    /**
     * 团队结构
     * @param $superior
     * @return int[]
     */
    public function teamStructure($superior)
    {
        $agentNumberOfDirectInvite = 0;
        $agentNumberOfIndirectInvite = 0;
        $subordinate = []; // 用户的下(和下下)级

        // 当前用户的下一级 (当前用户是他的直接邀请人)
        User::query()
            ->where('inviter_direct', $superior)
            ->select(['user_id'])
            ->each(function (User $user) use ($superior, &$agentNumberOfDirectInvite, &$subordinate) {
                $agentNumberOfDirectInvite ++; // 直接邀请人数
                $subordinate[] = $user['user_id'];

                // 存储用户直接邀请人
                Redis::hset('migrate:agent_direct_invitor', $user['user_id'], $superior);
            });

        // 当前用户的下下一级 (当前用户是他的间接邀请人)
        User::query()
            ->where('inviter_indirect', $superior)
            ->select(['user_id'])
            ->each(function (User $user) use (&$agentNumberOfIndirectInvite, &$subordinate) {
                $agentNumberOfIndirectInvite ++; // 间接邀请人数
                $subordinate[] = $user['user_id'];
            });

        Redis::hset('migrate:agent_subordinate', $superior, json_encode($subordinate)); // 当前用户的下(和下下)级

        return [$agentNumberOfDirectInvite, $agentNumberOfIndirectInvite];
    }
}
